#ifndef OMG_TDDS_DOMAIN_DOMAIN_PARTICIPANT_HPP_
#define OMG_TDDS_DOMAIN_DOMAIN_PARTICIPANT_HPP_

/* Copyright (c) 2009-2010, Real-Time Innovations, Inc.
 * Copyright (c) 2010, Object Management Group, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - Neither the names of the above copyright holders nor the names of their
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL A COPYRIGHT HOLDER OR CONTRIBUTOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


namespace tdds { namespace domain {


/**
 * The <code>DomainParticipant</code> object plays several roles:
 * <ul>
 *   <li>
 *     It represents the participation of the application on a communication
 *     plane that isolates applications running on the same set of physical
 *     computers from each other. A domain establishes a virtual network
 *     linking all applications that share the same domainId and isolating
 *     them from applications running on different domains. In this way,
 *     several independent distributed applications can coexist in the same
 *     physical network without interfering, or even being aware of each
 *     other.
 *   </li>
 *   <li>
 *     It provides access to the information available in a domain and
 *     currently discovered by the discovery service. This class also
 *     provides administration services in the domain, offering operations
 *     that allow the application to "ignore" locally any information about a
 *     given participant (ignore_participant), publication
 *     (ignore_publication), subscription (ignore_subscription), or topic
 *     (ignore_topic).
 *   </li>
 * </ul>
 */
template <typename DELEGATE>
class DomainParticipant : public tdds::core::Entity<DELEGATE> {
    OMG_DDS_REFERENCE_TYPE(DomainParticipant)

public:
    typedef dds::core::StatusCondition<DomainParticipant> StatusConditionType;

public:

    using dds::core::Entity::qos;

    /**
     * Return the <code>DomainParticipantQos</code> setting for this instance.
     *
     * @return the qos setting.
     */
    const dds::domain::DomainParticipantQos
    qos() const;

    void qos(const dds::domain::DomainParticipantQos& the_qos);

    /**
     * This operation retrieves the domain_id used to create the
     * <code>DomainParticipant</code>. The domain_id identifies the DDS domain
     * to which the <code>DomainParticipant</code> belongs.
     * As described in the introduction to Section 7.1.2.2.1,
     * DomainParticipant Class, on page 22 each DDS domain represents a
     * separate data communication plane” isolated from other domains.
     *
     * @return the domain id
     */
    dds::domain::DomainId domain_id() const;


    /**
     * This operation manually asserts the liveliness of the DataWriter.
     * This is used in combination with the LIVELINESS QoS policy
     * (see Section 7.1.3, Supported QoS, on page 96) to indicate to the
     * Service that the entity remains active.
     * This operation need only be used if the LIVELINESS setting is either
     * MANUAL_BY_PARTICIPANT or MANUAL_BY_TOPIC. Otherwise, it has no effect.
     *
     * <b>Note</b> Writing data via the write operation on a DataWriter
     * asserts liveliness on the DataWriter itself and its DomainParticipant.
     * Consequently the use of assert_liveliness is only needed if the
     * application is not writing data regularly.
     */
    void
    assert_liveliness();


    /**
     * This operation checks whether or not the given a_handle represents
     * an Entity that was created from the DomainParticipant.
     * The containment applies recursively. That is, it applies both to
     * entities (TopicDescription, Publisher, or Subscriber) created directly
     * using the DomainParticipant as well as entities created using a
     * contained Publisher, or Subscriber as the factory, and so forth.
     *
     * @param handle the instance handle for which the containement
     *               relationship has to be checked.
     *
     * @return true if the handle belongs to an <code>Entity</code> belonging
     *              to this <code>DomainParticipant</code>
     */
    bool
    contains_entity(const dds::core::InstanceHandle& handle);

    /**
     * This operation returns the current value of the time that the service
     * uses to time-stamp data writes and to set the reception timestamp
     * for the data updates it receives.
     */
    const dds::core::Time
    current_time();

    void ignore_publication(const dds::core::InstanceHandle &handle);

    /**
     * This operation allows an application to instruct the Service to locally
     * ignore a remote subscription; a subscription is defined by the 
     * association of a topic name, and user data and partition set on the 
     * Subscriber (see the “DCPSSubscription” built-in Topic in Section 7.1.5,
     * “Built-in Topics,” on page 134). After this call, any data received 
     * related to that subscription will be ignored.
     * The DataReader to ignore is identified by the handle argument. 
     * This handle is the one that appears in the Sample retrieved when 
     * reading the data-samples from the built-in DataReader to the 
     * “DCPSSubscription” topic.
     * The ignore_subscription operation is not required to be reversible. 
     * The Service offers no means to reverse it. Possible error codes 
     * returned in addition to the standard ones: OUT_OF_RESOURCES.
     *
     * @param the handle for the subscription to ignore.
     */
    void ignore_subscription(const dds::core::InstanceHandle &handle);

public:
    const dds::pub::PublisherQos default_publisher_qos() const;
    void default_publisher_qos(const dds::pub::PublisherQos& qos);
    void default_publisher_qos(const std::string& qos_library_name,
                                   const std::string& qos_profile_name);

    const dds::sub::SubscriberQos default_subscriber_qos() const;
    void default_subscriber_qos(const dds::sub::SubscriberQos& qos);
    void default_subscriber_qos(const std::string& qos_library_name,
                                    const std::string& qos_profile_name);

    const dds::topic::TopicQos default_topic_qos() const;
    void default_topic_qos(const dds::topic::TopicQos& qos);
    void default_topic_qos(const std::string& qos_library_name,
                               const std::string& qos_profile_name);

public:
    /**
     * This operation creates a Publisher with default QoS.
     */
    dds::pub::Publisher create_publisher();

    /**
     * This operation creates a Publisher with the desired QoS policies
     * and attaches to it the specified PublisherListener.
     * If the specified QoS policies are not consistent, the operation
     * will fail and an exception will be thrown.
     */
    dds::pub::Publisher create_publisher(
        const dds::pub::PublisherQos& qos,
        const dds::pub::PublisherListener *a_listener   = NULL,
        const dds::core::status::StatusMask& mask               = dds::core::status::StatusMask::all());

    /**
     * This operation creates a Publisher with the desired QoS policies
     * and attaches to it the specified PublisherListener.
     * If the specified QoS policies are not consistent, the operation
     * will fail and an exception will be thrown.
     */
    dds::pub::Publisher create_publisher(
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        const dds::pub::PublisherListener* a_listener   = NULL,
        const dds::core::status::StatusMask& mask               = dds::core::status::StatusMask::all());
    
    dds::sub::Subscriber create_subscriber();
    dds::sub::Subscriber create_subscriber(
        const dds::sub::SubscriberQos& qos,
        const dds::sub::SubscriberListener *a_listener  = NULL,
        const dds::core::status::StatusMask& a_mask             = dds::core::status::StatusMask::all());
    dds::sub::Subscriber create_subscriber(
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        const dds::sub::SubscriberListener* a_listener  = NULL,
        const dds::core::status::StatusMask& a_mask             = dds::core::status::StatusMask::all());
    
    template <typename T>
    dds::topic::Topic<T> create_topic(
        const std::string &topic_name, 
        dds::type::TypeSupport<T> type = dds::type::TypeSupport<T>());
    template <typename T>
    dds::topic::Topic<T> create_topic(
        const std::string &topic_name, 
        dds::type::TypeSupport<T> type,
        const dds::topic::TopicQos& qos,
        dds::topic::TopicListener<T>* a_listener    = NULL,
        const dds::core::status::StatusMask& mask           = dds::core::status::StatusMask::all());
    template <typename T>
    dds::topic::Topic<T> create_topic(
        const std::string &topic_name, 
        dds::type::TypeSupport<T> type,
        const std::string& qos_library_name,
        const std::string& qos_profile_name,
        dds::topic::TopicListener<T>* a_listener    = NULL,
        const dds::core::status::StatusMask& mask           = dds::core::status::StatusMask::all());

#ifdef OMG_DDS_CONTENT_SUBSCRIPTION_SUPPORT
    template <typename T>
    dds::topic::ContentFilteredTopic<T> create_contentfilteredtopic(
        const std::string& name,
        const dds::topic::Topic<T>& related_topic,
        const std::string& filter_expression,
        const dds::core::StringSeq& expression_parameters);
#endif  // OMG_DDS_CONTENT_SUBSCRIPTION_SUPPORT
    
#ifdef OMG_DDS_CONTENT_SUBSCRIPTION_SUPPORT
    template <typename T>
    dds::topic::MultiTopic<T> create_multitopic(
        const std::string& name,
        const std::string& type_name, 
        const std::string& subscription_expression,
        const dds::core::StringSeq& expression_parameters);
#endif  // OMG_DDS_CONTENT_SUBSCRIPTION_SUPPORT

    // --- Entity methods: --- //
public:
    /**
     * This method closes the entity and releases all resources associated with
     * DDS, such as threads, sockets, buffers, etc. Any attempt to invoke
     * methods on a closed entity will raise an AlreadyClosedError.
     */
    virtual void close();

    StatusConditionType status_condition();

    void listener(dds::domain::DomainParticipantListener* l,
                  const dds::core::status::StatusMask& mask =
                          dds::core::status::StatusMask::all());
    
    dds::domain::DomainParticipantListener* listener() const;
};

} } /* namespace tdds / namespace domain */

#endif /* OMG_TDDS_DOMAIN_DOMAIN_PARTICIPANT_HPP_ */
